﻿#pragma once

#include "any.hpp"


#include <string>
#include <vector>
#include <map>
#include <iostream>

using std::string;
using std::vector;
using std::map;
using Any = linb::any;
using linb::any_cast;
class Parameter
{
private:
	struct Schema
	{

	//private:
		bool _required = true;
		string _doc;
		linb::any _value;
		vector<linb::any> _options;
	public:
		Schema& required(bool _ = true)
		{
			this->_required = _;
			return *this;
		}
		Schema& doc(const string& _)
		{
			this->_doc = _;
			return *this;
		}
	};

public:
	Parameter() {};
	~Parameter() {};

	Parameter operator=(const Parameter& rhs)
	{
		return *this;
	}
	using DataType = map<string, Schema>;
	using iterator = DataType::iterator;
	using const_iterator = DataType::const_iterator;

	iterator begin() { return _data.begin(); }
	const_iterator cbegin() const { return _data.cbegin(); }

	iterator end() { return _data.end(); }
	const_iterator cend() { return _data.cend(); }

	bool have(const string& name);
	//{
	//	return _data.find(name) != _data.end();
	//}

	template<typename T> 
	void set(const string& name, T value, const string& doc="")
	{
		if (!have(name))
		{
			std::cerr << "参数 " << name << "不存在\n";
			exit(0);
		}
		if (_data[name]._value.empty())
		{
			_data[name]._value = value;
		}
		any_cast<T&>(_data[name]._value) = value;
	}

	//template<typename T>
	//any& set(const string& name)
	//{
	//	if (!have(name))
	//	{
	//		std::cerr << "参数 " << name << "不存在\n";
	//		exit(0);
	//	}
	//	if (_data[name]._value.empty())
	//	{
	//		return _data[name]._value;
	//	}
	//	return any_cast<T&>(_data[name]._value);
	//}

	template<typename T>
	T get(const string& name)
	{
		if (!have(name))
		{
			std::cerr << "参数 " << name << "不存在\n";
			exit(0);
		}
		if (_data[name]._value.empty())
		{
			std::cerr << "参数 " << name << "未初始化\n";
			exit(0);
		}
		return any_cast<T>(_data[name]._value);
	}

	
	Schema& add(const string& name)
	{
		if (have(name))
		{
			std::cerr << "参数 " << name << "存在\n";
			exit(0);
		}
		Schema schema{};
		_data.insert({ name, schema });
		return _data[name];
	}

	template<typename T>
	Schema& add(const string& name, T value)
	{
		this->add(name);
		_data[name]._value = value;
		return _data[name];
	}
	
	void PrintSchema(std::ostream& out, const Schema& schema)
	{
		Any a = 1;
		//out << schema._value << "  " << schema._required << "   " << schema._required;
	}


private:
	DataType _data;
};
